package com.miya.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.miya.demo.common.constant.WechatConstant;
import com.miya.demo.common.util.OkHttpUtil;
import com.miya.demo.config.MapConfig;
import com.miya.demo.model.dto.map.GaodeMapGeoDTO;
import com.miya.demo.model.dto.map.GaodeMapIpDTO;
import com.miya.demo.model.dto.map.GaodeMapRegeoDTO;
import com.miya.demo.model.vo.map.*;
import com.miya.demo.service.GaodeMapService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 高德地图服务impl
 *
 * @author CaiXiaowei
 * @date 2022/09/23
 */
@Service
public class GaodeMapServiceImpl implements GaodeMapService {

    @Resource
    private MapConfig mapConfig;

    /**
     * 高德逆地理编码（高德经纬度转地址）
     *
     * @param locLongitude 经度
     * @param locLatitude  纬度
     * @return {@link GaodeMapAddressVO}
     */
    @Override
    public GaodeMapAddressVO getAddressByLocation(String locLongitude, String locLatitude) {
        GaodeMapRegeoDTO regeoDTO = new GaodeMapRegeoDTO();
        regeoDTO.setKey(mapConfig.getGaodeKey());
        regeoDTO.setLocation(StrUtil.join(StrUtil.COMMA, locLongitude, locLatitude));
        Map<String, Object> paramMap = BeanUtil.beanToMap(regeoDTO);
        GaodeMapReGeoVO gaodeMapReGeoVO = OkHttpUtil.builder()
                .url(WechatConstant.GAODE_REGEO_URL)
                .get(paramMap)
                .sync(GaodeMapReGeoVO.class);
        GaodeMapAddressVO addressVO = new GaodeMapAddressVO();

        GaodeMapReGeoVO.RegeocodeBean.AddressComponentBean addressComponent = gaodeMapReGeoVO.getRegeocode().getAddressComponent();
        Optional.ofNullable(addressComponent).ifPresent(addressComponentBean -> {
            addressVO.setProvince(addressComponent.getProvince());
            addressVO.setDistrict(addressComponent.getDistrict());
            addressVO.setTownship(addressComponent.getTownship());
            //5.解决直辖市问题
            String city = addressComponent.getCity();
            if (new ArrayList<>().toString().equals(city)) {
                addressVO.setCity(gaodeMapReGeoVO.getRegeocode().getAddressComponent().getProvince());
            } else {
                addressVO.setCity(city);
            }
            GaodeMapReGeoVO.RegeocodeBean reGeoCode = gaodeMapReGeoVO.getRegeocode();
            Optional.ofNullable(reGeoCode).ifPresent(reGeoCodeBean -> {
                addressVO.setAddressDetail(reGeoCodeBean.getFormattedAddress());
            });
        });

        return addressVO;
    }

    /**
     * 根据ip获得地址信息
     *
     * @param ip ip
     * @return {@link GaodeMapAddressVO}
     */
    @Override
    public GaodeMapAddressVO getAddressByIp(String ip) {
        GaodeMapAddressVO addressVO = new GaodeMapAddressVO();
        GaodeMapIpDTO ipDTO = new GaodeMapIpDTO(mapConfig.getGaodeKey(), ip);
        Map<String, Object> paramMap = BeanUtil.beanToMap(ipDTO);
        GaodeMapIpVO gaodeMapIpVO = OkHttpUtil.builder()
                .url(WechatConstant.GAODE_IP_URL)
                .get(paramMap)
                .sync(GaodeMapIpVO.class);
        BeanUtil.copyProperties(gaodeMapIpVO, addressVO, CopyOptions.create().ignoreNullValue());
        return addressVO;
    }

    /**
     * 高德地理编码（高德地址转经纬度）
     *
     * @param address 地址
     * @return {@link GaodeMapLocationVO}
     */
    @Override
    public GaodeMapLocationVO getLocationByAddress(String address) {
        List<GaodeMapLocationVO> locationByAddressBatch = requestAMapLocationByAddressBatch(new GaodeMapGeoDTO(mapConfig.getGaodeKey(), address, false));
        return locationByAddressBatch.stream().findFirst().orElse(null);
    }

    private List<GaodeMapLocationVO> requestAMapLocationByAddressBatch(GaodeMapGeoDTO gaodeMapGeoDTO) {
        //1.初始化出参结合
        List<GaodeMapLocationVO> thirdPartAMapLocationByAddressResList = new ArrayList<>();

        //2.发送请求，获取JSON
        Map<String, Object> paramMap = BeanUtil.beanToMap(gaodeMapGeoDTO, true, true);
        String json = OkHttpUtil.builder()
                .url(WechatConstant.GAODE_GEO_URL)
                .get(paramMap)
                .sync();

        Optional.ofNullable(json).ifPresent(jsonResult -> {
            //3.将JSON转换为对象
            GaodeMapGeoVO gaodeMapGeoVO = JSONUtil.toBean(jsonResult, GaodeMapGeoVO.class);

            //4.获取地理编码信息列表
            List<GaodeMapGeoVO.Geocode> geocodes = gaodeMapGeoVO.getGeocodes();

            //5.进行遍历，并封装出参
            geocodes.stream().filter(geoCode -> CollectionUtil.isNotEmpty(geoCode.getLocation())).collect(Collectors.toList()).forEach(geoCode -> {
                GaodeMapLocationVO locationVO = new GaodeMapLocationVO();
                locationVO.setLongitude(geoCode.getLocation().get(0));
                locationVO.setLatitude(geoCode.getLocation().get(1));
                locationVO.setFormattedAddress(geoCode.getFormatted_address());
                locationVO.setCountry(geoCode.getCountry());
                locationVO.setProvince(geoCode.getProvince());
                locationVO.setCity(geoCode.getCity());
                locationVO.setCityCode(geoCode.getCitycode());
                locationVO.setDistrict(geoCode.getDistrict());
                locationVO.setStreet(geoCode.getStreet());
                locationVO.setNumber(geoCode.getNumber());
                locationVO.setAdCode(geoCode.getAdcode());
                locationVO.setLevel(geoCode.getLevel());
                thirdPartAMapLocationByAddressResList.add(locationVO);
            });
        });


        return thirdPartAMapLocationByAddressResList;
    }
}
